/**
 * @projectName: petJoyHome
 * @author: 小飞
 * @description: TODO
 * @date: 2024/3/2 20:02
 * @version: 1.0
 */
package com.home.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.home.constant.*;
import com.home.dto.CreateUserDTO;
import com.home.dto.LoginDTO;
import com.home.dto.PageQueryDTO;
import com.home.entity.LoginUser;
import com.home.entity.RoleMenu;
import com.home.entity.User;
import com.home.entity.UserRole;
import com.home.exception.LoginFailedException;
import com.home.exception.UserNameExistException;
import com.home.mapper.RoleMenuMapper;
import com.home.mapper.UserMapper;
import com.home.mapper.UserRoleMapper;
import com.home.properties.JwtProperties;
import com.home.result.PageResult;
import com.home.service.UserService;
import com.home.utils.JwtUtil;
import com.home.utils.RedisUtil;
import com.home.utils.SecurityContextUtil;
import com.home.vo.LoginUserVo;
import com.home.vo.PageUserVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private final AuthenticationManager userAuthenticationManager;

    private final RedisUtil redisUtil;

    private final JwtProperties jwtProperties;

    private final UserMapper userMapper;

    private final UserRoleMapper userRoleMapper;

    private final RoleMenuMapper roleMenuMapper;

    @Override
    public LoginUserVo login(LoginDTO loginDTO) {
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(loginDTO.getUsername(), loginDTO.getPassword());
        Authentication authentication = userAuthenticationManager.authenticate(usernamePasswordAuthenticationToken);
        if (Objects.isNull(authentication)) {
            throw new LoginFailedException(MessageConstant.PASSWORD_ERROR);
        }
        //获取loginUser
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        loginUser.getUser().setPassword(null);
        redisUtil.setRedisObject(TokenConstant.USER_TOKEN_SECRET + loginUser.getUser().getId().toString(), loginUser, 2, TimeUnit.HOURS);
        Map<String, Object> map = new HashMap<>();
        map.put(JwtConstant.U_ID, loginUser.getUser().getId());
        String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), map);
        LoginUserVo loginUserVo = new LoginUserVo();
        //属性拷贝
        BeanUtil.copyProperties(loginUser.getUser(), loginUserVo);
        loginUserVo.setToken(token);
        return loginUserVo;
    }

    /**
     * 分页查询用户信息
     *
     * @param pageQueryDTO
     * @return
     */
    @Override
    public PageResult getPageUser(PageQueryDTO pageQueryDTO) {
        Page<User> page = new Page<>(pageQueryDTO.getPageNumber() == null ? 1 : pageQueryDTO.getPageNumber(), pageQueryDTO.getPageSize() == null ? 20 : pageQueryDTO.getPageSize());
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(pageQueryDTO.getUsername() != null && !pageQueryDTO.getUsername().isEmpty(), User::getUsername, pageQueryDTO.getUsername());
        lambdaQueryWrapper.eq(pageQueryDTO.getStatus() != null, User::getStatus, pageQueryDTO.getStatus());
        lambdaQueryWrapper.eq(pageQueryDTO.getSex() != null, User::getSex, pageQueryDTO.getSex());
        List<String> permissions = SecurityContextUtil.getLoginUser().getPermissions();
        //todo 判断该用户是否是管理该社团的人员
        if (permissions.contains(PermissionMessageConstant.SCHOOL_ADMIN)){
            // todo 根据传进来的社团id直接查对应的用户信息

        }else if(permissions.contains(PermissionMessageConstant.COLLEGE_ADMIN)){
            //todo 判断传进来的社团id是否从属该学院(是就下走，不是就返回)

            // todo 根据传进来的社团id直接查对应的用户信息

        }else if(permissions.contains(PermissionMessageConstant.INSTRUCTOR)){
            // todo 判断该用户是否为该社团的管理人员

        }else if(permissions.contains(PermissionMessageConstant.CLUB_COMMANDER)){
            // todo 判断该用户是否为该社团的负责人
        }else {
            // todo 其他情况
        }
        IPage<User> userIPage = userMapper.selectPage(page, lambdaQueryWrapper);
        List<PageUserVo> pageUserVos = new ArrayList<>();
        userIPage.getRecords().forEach(user -> {
            PageUserVo pageUserVo = new PageUserVo();
            List<UserRole> userRoles = userRoleMapper.selectList(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, user.getId()));
            if (!userRoles.isEmpty()){
                List<RoleMenu> roleMenus = roleMenuMapper.selectBatchIds(userRoles.stream().map(UserRole::getRoleId).collect(Collectors.toList()));
                user.setRoleTypes(roleMenus.stream().map(RoleMenu::getId).map(Long::intValue).collect(Collectors.toList()));
            }
            BeanUtil.copyProperties(user, pageUserVo);
            pageUserVos.add(pageUserVo);
        });
        return new PageResult(userIPage.getTotal(), pageUserVos);
    }

    /**
     * 新增用户
     *
     * @param createUserDTO
     */
    @Override
    public void createUser(CreateUserDTO createUserDTO) {
        User user = new User();
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getUsername, createUserDTO.getUsername());
        if (userMapper.selectOne(lambdaQueryWrapper) != null) {
            throw new UserNameExistException(MessageConstant.ACCOUNT_EXISTS);
        }
        BeanUtil.copyProperties(createUserDTO, user);
        user.setCreateUser(SecurityContextUtil.getLoginUser().getUser().getId());
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
        user.setStatus(StatusConstant.ENABLED);
        userMapper.insert(user);
    }
}
